*******************************************************************************
* List Manager/LineEdit Demo
*
* (C)  Copyright Apple Computer, Inc. 1988
* All rights reserved.
*
* by Keith Rollin and Jim Mensch
* September 1, 1988
*
* This program demonstrates the use of lists and LineEdit items in a window. It
* uses controls to create, rename, remove and sort items in a list, and uses a
* LineEdit item to enter new and rename old items. Cut, Copy, Paste, and Clear
* are supported.
*
* Demo Index:
*	Creating and changing lists
*	Simple button controls in a window
*	LineEdit Event handling
*	Cut, Copy, Paste, and Clear
*
*
* Files: System macros and equates.
*        Lists.Inits.aii
*
*
* Modification History:
*
* Version 1.0	Mensch & Rollin
*
*      September 1, 1988
*
*      First Release
*
*******************************************************************************
	eject
	
**********************************************************************
*                                                                    *
*             Apple IIGS Source Code Sampler, Volume I               *
*                                                                    *
*             Copyright (c) Apple Computer, Inc. 1988                *
*                       All Rights Reserved                          *
*                                                                    *
*            Written by Apple II Developer Tech Support              *
*                                                                    *
*                                                                    *
*                                                                    *
*  ----------------------------------------------------------------  *
*                                                                    *
*     This program and its derivatives are licensed only for         *
*     use on Apple computers.                                        *
*                                                                    *
*     Works based on this program must contain and                   *
*     conspicuously display this notice.                             *
*                                                                    *
*     This software is provided for your evaluation and to           *
*     assist you in developing software for the Apple IIGS           *
*     computer.                                                      *
*                                                                    *
*     DISCLAIMER OF WARRANTY                                         *
*                                                                    *
*     THE SOFTWARE IS PROVIDED "AS IS" WITHOUT                       *
*     WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,               *
*     WITH RESPECT TO ITS MERCHANTABILITY OR ITS FITNESS             *
*     FOR ANY PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO             *
*     THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH            *
*     YOU.  SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU (AND            *
*     NOT APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE)               *
*     ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING,             *
*     REPAIR OR CORRECTION.                                          *
*                                                                    *
*     Apple does not warrant that the functions                      *
*     contained in the Software will meet your requirements          *
*     or that the operation of the Software will be                  *
*     uninterrupted or error free or that defects in the             *
*     Software will be corrected.                                    *
*                                                                    *
*     SOME STATES DO NOT ALLOW THE EXCLUSION                         *
*     OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY              *
*     NOT APPLY TO YOU.  THIS WARRANTY GIVES YOU SPECIFIC            *
*     LEGAL RIGHTS AND YOU MAY ALSO HAVE OTHER RIGHTS                *
*     WHICH VARY FROM STATE TO STATE.                                *
*                                                                    *
*                                                                    *
**********************************************************************
	eject
	
	PRINT NOGEN,NOHDR

	STRING ASIS

	PRINT PUSH,OFF
	INCLUDE 'M16.Util'
	INCLUDE 'M16.ProDOS'
	INCLUDE 'M16.MiscTool'
	INCLUDE 'M16.QUICKDRAW'
	INCLUDE 'E16.Quickdraw'
	INCLUDE 'M16.MEMORY'
	INCLUDE 'E16.Memory'
	INCLUDE 'M16.EVENT'
	INCLUDE 'E16.EVENT'
	INCLUDE 'M16.LOCATOR'
	INCLUDE 'M16.Menu'
	INCLUDE 'M16.Control'
	INCLUDE 'E16.Control'
	INCLUDE 'M16.Window'
	INCLUDE 'E16.Window'
	INCLUDE 'M16.Dialog'
	INCLUDE 'E16.Dialog'
	INCLUDE 'M16.LineEdit'
	INCLUDE 'M16.IntMath'
	INCLUDE 'M16.Scrap'
	INCLUDE 'M16.Desk'
	INCLUDE 'M16.Texttool'
	Include 'E16.List'
	Include 'M16.List'
	PRINT POP

*******************************************************************************
*
*    Equates used in this program.
*
*******************************************************************************
DPHandle	equ 0	; Handle to Tool Direct Page area
DPPointer	equ DPHandle+4	; Pointer to Tool Direct Page area
deref	equ DPPointer+4	; Temporary Handle dereference area
TempLong	equ deref+4
TempWord	equ TempLong+4

ScreenMode	equ Mode640
ScreenWidth	equ 640


	EJECT
*******************************************************************************
*
Main	PROC
*
* Description:	This is the main routine. It calls routines to Initialize
*	the tools, initialize application specific data, run the
*	main EventLoop, close the application, and close the tools.
*	Then it calls the ProDOS Quit command.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:
	import InitTools
	import InitApp
	import EventLoop
	import CloseApp
	import CloseTools
	import QuitParms
*
* Entry Points:	NONE
*
*******************************************************************************

	jsr InitTools
	jsr InitApp

	_ShowCursor

	jsr EventLoop

	jsr CloseApp
	jsr CloseTools

	_Quit QuitParms

	ENDP

	EJECT
*******************************************************************************
*
Globals	Record
*
* Description:	Holder of all of our data.
*
*
* Inputs:	N/A
*
* Outputs:	N/A
*
* External Refs:
	import PrUpdate
	import PrOldUpdate
*
* Entry Points:
	export QuitParms	; used by Main
*
*******************************************************************************
*
* Standard global data
*
*******************************************************************************

TitleString	str 'Apple IIgs List Mgr/LineEdit Example Application'
AutString	str 'By Rollin and Mensch Apple DTS ©1988 Apple Computer'
VersString	str 'Version: 1.0'

MenuHeight	ds.B 2	; Stored height of menu bar
MyID	ds.B 2	; Application ID
MyDP	ds.B 2	; My direct page storage

QuitFlag	ds.W 1
QuitParms	dc.L 0	; Pathname of next app
	dc.W $00	; flags

EventRecord
EventWhat	ds.B 2
EventMessage	ds.B 4
EventWhen	ds.B 4
EventWhere	ds.B 4
EventModifiers	ds.B 2
TaskData	ds.B 4
TaskMask	dC.L $0000FFFF

	EJECT
*******************************************************************************
*
* Application specific global data
*
*******************************************************************************

; This is a list of pointers to the text that is used to create our menus. It
; is used by InitApp to find all of the menu templates and use them to create
; our menubar. This loop loads MenuPtrLen-4 into an index, gets the
; corresponding menu template pointer in this table, and uses that in a
; NewMenu call. It then decrements the index by 4, and repeats the procees
; until the index is negative.

MenuPtr	dc.l AppMenu
	dc.l FileMenu
	dc.l EditMenu
MenuPtrLen	equ *-MenuPtr


; Menu list: menu items should be numbered consecutivly starting from 250.
; As a convention, use 256 as about and 257 as Quit.

AppMenu	dc.B '$$@\N1',$0D
	dc.B '--About List Manager/LineEdit Demo...\N256V',$00
	dc.B '.'
FileMenu	dc.B '$$  File  \N2',$00
	dc.B '--Close Document\N255DV',$00
	dc.B '--Quit\N257*Qq',$00
	dc.B '.'
EditMenu	dc.B '$$  Edit  \N3',$00
	dc.B '--Undo\N250*ZzVD',$00
	dc.B '--Cut\N251*Xx',$00
	dc.B '--Copy\N252*Cc',$00
	dc.B '--Paste\N253*Vv',$00
	dc.B '--Clear\N254',$00
	dc.b '.'

ErrOut	ds.B 4
TempSave	ds.B 4
tempHndl	ds.B 4

;
;   Control definitions for use with new control
;
NumCtrls	dc.W 5
MyCtrlList	dc.L NewBRec,DelBRec,RepBRec,RstBRec,SortBRec

MyCtlHdls
NewBHdl	ds.B 4	; storage for returned handles
DelBHdl	ds.B 4
RepBHdl	ds.B 4
RstBHdl	ds.B 4
SortBHdl	ds.B 4
LEHandle	ds.B 4

NewBTitle	str 'New Entry'
DelBTitle	str 'Remove'
RepBTitle	str 'Replace'
RstBTitle	str 'UnHilite'
SortBTitle	str 'Sort'

NewBRect	dc.W 10,250,25,350
DelBRect	dc.W 30,250,45,350
RepBRect	dc.W 50,250,65,350
RstBRect	dc.W 70,250,85,350
SortBRect	dc.W 90,250,105,350
destRect	dc.w 100,20,110,224
viewRect	dc.w 97,10,113,234

NewBRec
	dc.L 0
	dc.L 1
	dc.L SimpleProc	; defproc = simple button
	dc.W 0,0	; no params
	dc.W 1	; starting value
	dc.W BoldButton	; control flags
	dc.L NewBTitle	; pointer to title string
	dc.L NewBRect	; pointer to bounds rect
cRecSize	equ *-NewBRec	; size of my control record

DelBRec
	dc.L 0	; color table pointer
	dc.L 2	; refcon ( control dispatch number )
	dc.L SimpleProc	; defproc = simple button
	dc.W 0,0	; no params
	dc.W 1	; starting value
	dc.W SimpRound	; control flags
	dc.L DelBTitle	; pointer to title string
	dc.L DelBRect	; pointer to bounds rect


RepBRec
	dc.L 0	; color table pointer
	dc.L 3	; refcon ( control dispatch number )
	dc.L SimpleProc	; defproc = simple button
	dc.W 0,0	; no params
	dc.W 1	; starting value
	dc.W SimpRound	; control flags
	dc.L RepBTitle	; pointer to title string
	dc.L RepBRect	; pointer to bounds rect

RstBRec
	dc.L 0	; color table pointer
	dc.L 4	; refcon ( control dispatch number )
	dc.L SimpleProc	; defproc = simple button
	dc.W 0,0	; no params
	dc.W 1	; starting value
	dc.W SimpRound	; control flags
	dc.L RstBTitle	; pointer to title string
	dc.L RstBRect	; pointer to bounds rect

SortBRec
	dc.L 0	; color table pointer
	dc.L 6	; refcon ( control dispatch number )
	dc.L SimpleProc	; defproc = simple button
	dc.W 0,0	; no params
	dc.W 1	; starting value
	dc.W SimpRound	; control flags
	dc.L SortBTitle	; pointer to title string
	dc.L SortBRect	; pointer to bounds rect


FullRect	dc.W 0,0,120,400
ListCtlHndl	ds.B 4

MemberSize	equ 10

MyList		; List record
ListRect	dc.W 10,10,92,210	; list is 200x80
MLNum	dc.W 5	; number of members in the list
	dc.W 8	; max seen at once
	dc.W selectOnlyOne	; single selection/pascal strings
	dc.W 1	; list start
	dc.L 0	; list control handle
	dc.L 0	; no list draw
	dc.W 10	; list member height
	dc.W MemberSize	; list record size
	dc.L MyData	; pointer to member list
	dc.L 5	; list ref con (control dispatch number)
	dc.L 0	; color table pointer (default colors)

;
; These are the data records for each member of the list. Each one consists of:
;      - a pointer to the string to be printed
;      - a word of bit flags (only the lower byte is used; the upper byte is
;        used as padding to make data access easier.
;      - a 4 byte space to hold a handle for those items whose names have been
;        stored in the heap with the Memory Manager
; We define only 5 members initially. However, we reserve space in the member
; record array for 30 members total.

MyData	dc.L member1
	dc.w 0
	dc.l 0
	dc.L member2
	dc.w 0
	dc.l 0
	dc.L member3
	dc.w 0
	dc.l 0
	dc.L member4
	dc.w 0
	dc.l 0
	dc.L member5
	dc.w 0
	dc.l 0
	ds.B 25*Membersize	; and at the end, room for 25 more
MyDataTSize	equ *-MyData

member1	str 'Member 1'
member2	str 'Member 2'
member3	str 'Member 3'
member4	str 'Member 4'
member5	str 'Member 5'

MyWindow	dc.W WindEnd-*	; size of paramBlock
	dc.W %0010000000100000 ; frame bits : alert, vis
	dc.L 0	; no title bar, no title...
	dc.L 0	; ref con 0
	dc.W 0,0,0,0	; zoomed rect
	dc.L 0	; color table = default
	dc.W 0,0	; scroll bar XY origin
	dc.W 0,0	; no scroll no max...
	dc.W 0,0	; No zooming...
	dc.W 0,0	; no scrolling
	dc.W 0,0	; no paging....
	dc.L 0	; no info bar, no ref con
	dc.W 0	; info bar height (none...)
	dc.L 0	; Frame defproc, NIL=standard
	dc.L 0	; no info bar def proc
	dc.L 0	; no auto updates..(yet)
	dc.W 20,20,140,420	; bounds rect...
	dc.L $FFFFFFFF	; plane= on top...
	dc.L 0	; NIL storage pointer
WindEnd	equ *
WindPointer	ds.B 4

	EndR


	EJECT
*******************************************************************************
*
InitApp	PROC
*
* Description:	Perform any application specific initialization.
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	
	import CreateList
	import CreateCtrls
	import NoSelection
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	stz QuitFlag

	pha
	pha
	PushLong #MyWindow
	_NewWindow
	PullLong WindPointer

	PushLong WindPointer
	_SetPort

	jsr CreateList	; make a list in the window
	jsr CreateCtrls
	jsr NoSelection	; reset the buttons to unselected

	PushWord #255	; deactivate the delete button
	PushLong NewBHdl	; handle to the delete button
	_HiLiteControl

	PushWord #25	; set the size of LineEdit's
	_LESetScrapLen	; scrap to 25 characters

	rts
	ENDP

	EJECT
*******************************************************************************
*
CloseApp	PROC
*
* Description:	Close down things. This disposes of all items and memory
*	that we allocated.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	rts
	ENDP

	EJECT
*******************************************************************************
*
EventLoop	PROC
*
* Description:	Main Event Loop. Handle things until user selects Quit.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:
	import MenuSelect
	import ignore
	import doUpdate
	import InContent
	import doActivate
	import doKey
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	PushLong LEHandle	; flash the LineEdit cursor
	_LEIdle

	pha	; Push on space for TaskMaster result
	PushWord #EveryEvent ; GetNextEvent mask
	PushLong #EventRecord ; Pointer to Event Record
	_TaskMaster

	pla	; Get TaskMaster result
	beq EventLoop	; Remove if you want to use null events
	asl A	; Turn it into an index
	tax
	jsr (TaskTable,x)	; Call appropriate event handler

	lda QuitFlag	; Quit selected?
	beq EventLoop	; no - keep looping

	rts	; yes- leave the program

TaskTable	dc.W Ignore	; 0 Null
	dc.W Ignore	; 1 MouseDown
	dc.W Ignore	; 2 MouseUp
	dc.W doKey	; 3 KeyDown
	dc.W Ignore	; 4 undefined
	dc.W doKey	; 5 AutoKey
	dc.W doUpdate	; 6 Update
	dc.W Ignore	; 7 undefined
	dc.W doActivate	; 8 Activate
	dc.W Ignore	; 9 Switch
	dc.W Ignore	; 10 Desk accessory
	dc.W Ignore	; 11 Device driver
	dc.W Ignore	; 12 ap
	dc.W Ignore	; 13 ap
	dc.W Ignore	; 14 ap
	dc.W Ignore	; 15 ap
	dc.W Ignore	; TASK 0 indesk
	dc.W MenuSelect	; TASK 1 in menuBar
	dc.W Ignore	; TASK 2 in system window
	dc.W InContent	; TASK 3 in content
	dc.W Ignore	; TASK 4 in Drag
	dc.W Ignore	; TASK 5 in grow
	dc.W Ignore	; TASK 6 in goaway
	dc.W Ignore	; TASK 7 in zoom
	dc.W Ignore	; TASK 8 in info bar
	dc.W MenuSelect	; TASK 9 in special	menu
	dc.W Ignore	; TASK 10 in NDA
	dc.W Ignore	; TASK 11 in frame
	dc.W Ignore	; TASK 12 in drop

	ENDP

	EJECT
*******************************************************************************
*
MenuSelect	PROC
*
* Description:	This routine is called when TaskMaster returns a menu
*	event. It takes the menu item that was hit and calculates
*	an offset into the menu dispatch table. It then calls that
*	routine and unhilites the menu when it is done.
*
* Inputs:	TaskData holds menu item selected.
*
* Outputs:	NONE
*
* External Refs:
	import ignore
	import doAbout
	import doQuit
	import doCut
	import doCopy
	import doPaste
	import doClear
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	lda TaskData	; Get the ID of the menu item selected.
	sec	; Turn it into an index by subtracting
	sbc #250	; the starting ID number (25) and mul-
	asl a	; tiplying by 2 (each table entry con-
	tax	; sists of 2 bytes).
	jsr (menuTable,x)	; Call the routine behind it.

	PushWord #0	; Routine done - unhilite the menubar.
	PushWord taskData+2
	_HiLiteMenu

	rts

MenuTable	dc.W Ignore	; undo
	dc.W doCut	; cut
	dc.W doCopy	; copy
	dc.W doPaste	; paste
	dc.W doClear	; clear
	dc.W Ignore	; close
	dc.W doAbout
	dc.W doQuit
	ENDP

	EJECT
*******************************************************************************
*
Ignore	PROC
*
* Description:	Called when I want to ignore an event.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************

	rts
	ENDP

	EJECT
*******************************************************************************
*
doUpdate	PROC
*
* Description:	Called by the Main Event Loop to update a window's
*	contents.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	with Globals

	lda WindPointer	; first test to see that its our window
	ora WindPointer+2
	beq NotUp	; bad bad update event!

	PushLong WindPointer ; Prepare to update our window
	_BeginUpdate

	PushLong WindPointer ; draw all of the controls
	_DrawControls

	PushLong #ViewRect	; frame our lineEdit item
	_FrameRect

	PushLong LEHandle	; update the LineEdit item
	_LEUpdate

	PushLong WindPointer ; end updating of our window
	_EndUpdate

NotUp
	rts
	ENDP

	EJECT
*******************************************************************************
*
DoActivate	PROC
*
* Description:	This routine is called when our window is either coming
*	to front, or no longer being in front. Its main function
*	is to make the LineEdit item (in)active.
*
*
* Inputs:	Event record from TaskMaster
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	PushLong LEHandle
	lda EventModifiers
	and #activeFlag
	bne Activate
	_LEDeactivate
	bra done
Activate	_LEActivate
done
	rts
	ENDP

	EJECT
*******************************************************************************
*
doKey	PROC
*
* Description:	Called by the Main Event loop when a Keydown or AutoKey
*	Event occurs. If the RETURN key was hit, a hit on the
*	"New Item" button is simulated. Otherwise, the key press
*	is passed on to LEKey.
*
*
* Inputs:	Event record from TaskMaster
*
* Outputs:	LineEdit or List is modified
*
* External Refs:	
	import NewListItem
	import ckNewAndRep
*
* Entry Points:	NONE
*
*******************************************************************************
	with Globals

	lda EventMessage	; get the character pressed
	and #$007f	; clear the high if it's set
	cmp #$0D	; see if it's a <RETURN> 
	beq doCR	; if is one, simulate New Item hit
	PushWord EventMessage ; else, pass this on to LEKey
	PushWord EventModifiers
	PushLong LEHandle
	_LEKey

	jsr ckNewAndRep	; update the New and Replace buttons
	bra done

doCR
	PushWord #1	; Hilite the New button
	PushLong NewBHdl
	_HiLiteControl

	PushWord #0	; UnHilite the New button
	PushLong NewBHdl
	_HiLiteControl

	jsr NewListItem	; add the LineEdit text to the list.

done
	rts
	ENDP

	EJECT
*******************************************************************************
*
doEdit	PROC
*
* Description:	This block is really 4 routines to handle the Edit Menu.
*	Any Edit selections are passed on to the appropriate
*	LineEdit routine. Undo is currently not supported.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:
	import ckNewAndRep
*
* Entry Points:
	entry doCut
	entry doCopy
	entry doPaste
	entry doClear
*
*******************************************************************************
	with Globals

doCut	PushLong LEHandle	; Handle a "Cut" command
	_LECut
	bra done

doCopy	PushLong LEHandle	; Handle a "Copy" command
	_LECopy
	rts	; Don't update New and Replace buttons

doPaste	PushLong LEHandle	; Handle a "Paste" command
	_LEPaste
	bra done

doClear	PushLong LEHandle	; Handle a "Clear" command
	_LEDelete

done
	jsr ckNewAndRep	; update the New and Replace buttons

	rts
	ENDP

	EJECT
*******************************************************************************
*
InContent	PROC
*
* Description:	Called to handle clicks in a window's contents. FindControl
*	is called to determine on what, if any, control was hit.
*	If a control is hit, it is tracked, and the appropriate
*	routine is called to perform some action. If a control
*	is not hit, then a check is made to see if the LineEdit
*	item was hit. If so, then the click is passed on to LEClick
*	for handling.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:
	import NewListItem
	import DelListItem
	import RepListItem
	import RstListItem
	import ListHit
	import SortHit
*
* Entry Points:	NONE
*
*******************************************************************************
	with Globals

; First, find out where we clicked, and see if it was on a control

	pha	; result space
	PushLong #TempHndl
	PushLong EventWhere	; push the point
	PushLong WindPointer
	_FindControl
	pla
	bne IC0010	; hit a control! Track it!
	brl ckLine	; didn't hit control. See if we hit LE
IC0010
	pha	; result space
	PushLong EventWhere	; push mouse location
	PushLong #-1	; use default action procedure
	PushLong tempHndl	; push on handle to control hit
	_TrackControl	; track it
	pla	; where did we end up?
	bne IC0020	; still in control. Do something
	brl done	; out of control - exit this routine
IC0020
	cmp #simpleButton	; was it a button?
	beq CallCtlAction	; if so then handle it
	cmp #$88	; was it the list itself?
	bne done	; if not, then not a hit!

; We use a neat trick to determine what routine to call inresponse to a
; click on a control. We keep a 'routine index' in the refcon field of
; the control. When a click occurs on that control, we retrieve the
; refcon, turn it into an index into a table of routine pointers, get
; the pointer to a routine, and call it!

CallCtlAction
	pha	; space for result
	pha
	PushLong tempHndl	; get the item number from the refcon
	_GetCtlRefCon
	pla	; low byte of ref con
	plx	; (we don't use high byte)
	dec a	; subtract 1 from the refcon then
	asl a	; multiply by two to get table offset
	tax
	jsr (InCTable,x)	; jump to routine to handle this ctl
	bra done

; the mouse click did not occur in any of the regular controls. check to
; see if we clicked in the LineEdit item. If so, then call LEClick.

ckLine
	lda EventWhere	; Check to see if we clicked in the
	sta LocalPt	; LineEdit item. We do this by doing a
	lda EventWhere+2	; PtInRect. But we need the mouse in
	sta LocalPt+2	; local coordinates for this.

	PushLong #LocalPt
	_GlobalToLocal

	pha	; space for result
	PushLong #LocalPt
	PushLong #destRect
	_PtInRect	; see if we clicked in the edit item
	pla
	beq done	; no, we didn't, so leave

	PushLong #EventRecord ; yes we did, so call LEClick
	PushLong LEHandle
	_LEClick

done	rts

theRefCon	ds.B 4
InCTable	dc.W NewListItem,DelListItem,RepListItem
	dc.w RstListItem,ListHit,SortHit
LocalPt	ds.b 4

	ENDP

	EJECT
*******************************************************************************
*
NewListItem	PROC
*
* Description:	This routine is called by InContent if a click occured
*	on the "New" button. This routine determines is there
*	is enough room in the List record for another item. If
*	so, then a pointer to the next record is is created, and
*	AddMember is called to create a new List member using
*	the text from the LineEdit item. When that is done, we
*	tell the List Manager about it, and hilite the LineEdit
*	text so that it is easily changed into something else.
*
*
* Inputs:	NONE
*
* Outputs:	List updated. LineEdit text hilited.
*
* External Refs:
	import AddMember
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	lda MLNum	; # of elements in the list
	cmp #30	; do we have 30 already?
	bge NLIDone
	inc MLNum	; bump number of list entries

; Create a pointer to the next available space in the array of list record.
; This is done by multiplying the entry number the entry size. Multiplying
; is done by using the formula x = index*2 + index*8 (assuming that the size
; of a member record = 10)

	asl a	; multiply by 2
	sta TempWord	; save it for adding to *8 later
	asl a	; by four
	asl a	; and eight
	clc
	adc TempWord	; add in the times 2 part

; AddMember is the routine that we use to assign the text of the LineEdit
; item to a certain list record. All we have to do is enter with the
; accumulator holding a pointer to the right record, and it does the rest.

	jsr AddMember	; enter with record offset in Acc.

; Now tell the List Manager that we changed the list. Also, make sure that
; the item that is hilited in the list is STILL hilited. Do this by getting
; a pointer to the selected record, and passing it to _NewList

	pha	; long space for result
	pha
	PushLong #0	; start searching from the beginning
	PushLong #MyList
	_NextMember	; Get pointer Keep it on the stack
	PushLong #MyList	; pointer to my list record
	_NewList	; and make the new list!

; finally, hilite the line edit text so that we can easily change it later

	PushWord #0	; starting hilite range
	PushWord #255	; ending range
	PushLong LEHandle	; hande to the LE control
	_LESetSelect	; hilite it.

NLIDone
	rts

	ENDP

	EJECT
*******************************************************************************
*
DelListItem	PROC
*
* Description:	Called by InContent to remove a member from the list. It
*	is called only when there is a hilited list item to be
*	removed. This routine determines which item is hilited,
*	removes it from the list of member records, decrements
*	the number of members in the list, and redraws the list.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:
	import DisposeMember
	import NoSelection
	import ckNewAndRep
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	lda MLNum	; contains # of elements
	cmp #1	; do we have only 1 left?
	beq DLIDone	; if so then remove no more!
	dec MLNum	; adjust number of list entries

; DisposeMember finds the hilited list item, and puts an index to it in the
; X register. Also, if the string for the name of the member was stored in
; a handle, that handle is disposed of.

	jsr DisposeMember	; X set up for us on exit

loop
	lda MyData+MemberSize,x
	sta MyData,x	; move all data down 10 bytes
	inx	; ...in memory...
	inx	; ...two bytes at a time
	cpx #MyDataTSize	; is X bumped past the end of records?
	blt loop	; nope, keep looping

	PushLong #0	; Draw All members to redraw the list!
	PushLong #MyList
	_NewList	; and create the new list!

	jsr NoSelection	; now reset the apropriate buttons

DLIDone
	jsr ckNewAndRep
	rts

	ENDP

	EJECT
*******************************************************************************
*
RepListItem	PROC
*
* Description:	This routine is called from InContent to replace the text
*	of the hilited member with the text in the LineEdit Item.
*	It calls NextMember to find the hilited item, Disposes of
*	it, and then inserts a new item in the same place with the
*	new name.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:
	import DisposeMember
	import AddMember
	import NoSelection
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	pha	; space for result
	pha
	PushLong #0	; member to start looking at
	PushLong #MyList	; NOTE: This is the list template ptr
	_NextMember
	PullLong tempLong	; Pointer to item Selected

;
; Now that we know which member is being replaced, call DisposeMember to free
; up the memory that is allocated to it, and then call AddMember to fill in that
; member's record with new information.
;
	jsr DisposeMember
	txa
	jsr AddMember
	
; The information for the currently selected member has been changed. Now
; redraw the member.

	PushLong tempLong	; pass ptr of member to redraw
	PushLong #MyList
	_DrawMember

	jsr NoSelection	; now reset the apropriate buttons

; finally, hilite the line edit text so that we can easily change it later

	PushWord #0	; starting hilite range
	PushWord #255	; ending range
	PushLong LEHandle	; hande to the LE control
	_LESetSelect	; hilite it.

	rts
	ENDP

	EJECT
*******************************************************************************
*
RstListItem	PROC
*
* Description:	This routine is called by InContent to unhilite, or reset,
*	the currently selected item. It simply calls ResetMember
*	and then redraws that member.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	
	import NoSelection
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	pha	; space for result
	pha
	PushLong #MyList	; NOTE: This Is the list template ptr
	_ResetMember	; get item selected & unselect it
	PullLong tempLong	; Item Selected

; Obviously, at this point we could have omitted the PullLong/PushLong
; sequence to save some bytes, but we wanted to make sure that people were
; clear on what ResetMember returned, and what was passed to DrawMember.

	PushLong tempLong	; pass ptr of member to redraw
	PushLong #MyList	; now redraw the list
	_DrawMember

	jsr NoSelection	; turn off those buttons
	rts
	ENDP

	EJECT
*******************************************************************************
*
ListHit	PROC
*
* Description:	This routine is called by InContent when a hit on the List
*	item has occured. It activates the buttons we need when a
*	list item is selected, and gets the text of the item and
*	puts it into the LineEdit box. Finally, it hilites the
*	LineEdit text so that we can easily change it if we want.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	PushWord #0	; activate the delete button
	PushLong DelBHdl	; handle to the delete button
	_HiLiteControl

	PushWord #255	; now deactivate the replace button
	PushLong RepBHdl	; until we change edit item
	_HiLiteControl

	PushWord #0	; now activate the replace button
	PushLong RstBHdl
	_HiLiteControl

;
; Find out which member we hit, and insert its text into Line Edit
;
	pha	; space for result
	pha
	PushLong #0	; NIL to start at first entry
	PushLong #MyList	; pointer to my list record...
	_NextMember
	PullLong deref	; pointer to the next record

	ldy #2	; get the pointer to the string. We do
	lda [deref],y	; this by getting the pointer that the
	tax	; handle points to, and storing it back
	lda [deref]	; out in 'deref'.
	sta deref
	stx deref+2

	PushWord deref+2	; push on a pointer to the first character
	lda deref
	ina
	pha
	lda [deref]	; get the length of the string
	and #$00FF
	pha	; push on the length
	PushLong LEHandle
	_LESetText
	
; Now invalidate the area of the screen that contained the text so that
; LineEdit will redraw it.

	PushLong #destRect
	_InvalRect

; finally, hilite the line edit text so that we can easily change it later

	PushWord #0	; starting hilite range
	PushWord #255	; ending range
	PushLong LEHandle	; hande to the LE control
	_LESetSelect	; hilite it.

	rts
	ENDP

	EJECT
*******************************************************************************
*
SortHit	PROC
*
* Description:	This routine is called by InCotent when a click on the
*	Sort button occurs. It calls _SortList with a pointer to
*	a custom sorting routine, and then redraws the entire list.
*	The custom sorting procedure sorts the list in reverse
*	alphabetical order.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	PushLong #MySort	; Backwards sort routine
	PushLong #MyList
	_SortList

	PushLong #0	; redraw all members
	PushLong #MyList
	_DrawMember

	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
MySort
;
; This is the custom sorting routine. It is passed the pointers to
; 2 member records to compare. If the first member is 'less than' the
; second, then return with the carry set. Otherwise, the carry should
; be returned clear. When I am done, remove the parameters off of the
; stack and RTL back to the List Manager.
;
; The following are equates that I use for a 'local direct page'. I
; save off the register that points to the normal direct page, and
; put the value of the stack pointer into the Direct Page register.
; This way, the stack doubles as my direct page, and I can easily
; access the variables that were pushed on it. These equates repre-
; sent the information on the stack when my routine is called.
; Specifically, there is a 3 byte return address that will get me
; back to the list manager, and then there are 2 4-byte parameters
; that are pointers to the 2 members I have to compare.
;
RTLAddr	equ 1
memberA	equ RTLAddr+3
memberB	equ memberA+4

	tsc	; save the old Direct Page and
	phd	; make the stack our DP so that
	tcd	; we can use the params as pointers

	ldy #2	; replace the pointer to the first
	lda [MemberA],y	; member with the pointer to the
	tax	; string of that member.
	lda [MemberA]
	sta MemberA
	stx MemberA+2

	lda [MemberB],y	; do the same thing with the second
	tax	; member.
	lda [MemberB]
	sta MemberB
	stx MemberB+2

	SHORT	; Use 8-bit registers

	ldy #1	; Start comparing with char #1
cmpLoop
	lda [MemberB],y	; Now compare the string characters.
	cmp [MemberA],y	; If they are not equal, exit with the
	bne done	; carry is set appropriately.

	tya	; Check to see if we ended a string
	dec a
	cmp [memberA]	; end of Member A?
	beq AGreater	; if so, exit with carry set.

	cmp [memberB]	; end of Member B?
	beq BGreater	; if so, exit with carry clear.

	iny	; bump index to examine next char.
	bra cmpLoop

AGreater	sec
	bra done
BGreater	clc
done	LONG

	pld	; restore the Direct Page reg from stack.

	lda 0,s	; move the RTL address up so that it is
	sta 8,s	; in the right place after we remove the
	lda 2,s	; parameters.
	sta 10,s
	pla	; remove the pointers to the members from
	pla	; the stack.
	pla
	pla
	rtl

	ENDP

	EJECT
*******************************************************************************
*
ckNewAndRep	PROC
*
* Description:	Called from all over the place to correctly set the
*	activation states of the New and Replace buttons.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	with Globals

; Disable the replace button if no items are selected

	pha	; long space for result
	pha
	PushLong #0	; start searching from the beginning
	PushLong #MyList
	_NextMember
	pla	; was a pointer returned (if a long
	sta tempWord	; zero is return, there are not items
	pla	; selected).
	ora TempWord
	beq DisableRepItem

	PushWord #0	; activate the replace button
	bra FixRepButton

DisableRepItem
	PushWord #255	; deactivate the replace button

FixRepButton
	PushLong RepBHdl
	_HiLiteControl

; Enable or disable the New entry button depending on whether or not there
; is any text in the LineEdit buffer.

	pha
	PushLong LEHandle
	_LEGetTextLen
	pla
	beq disableIt	; if no length, then no text.

	PushWord #0	; activate the New button
	bra CallHilite

disableIt
	PushWord #255	; deactivate the New button

CallHilite
	PushLong NewBHdl
	_HiLiteControl

	RTS
	ENDP

	EJECT
*******************************************************************************
*
AddMember	PROC
*
* Description:	Utility routine called from NewListItem and RepListItem to
*	insert a new member. This routine will read the entry in
*	the LineEdit record, store it in a handle, and create a
*	new member record at the spot that is specified by the
*	accumulator. It does not redraw the list.
*
*
* Inputs:	A = the offset to the record that you want to change.
*
* Outputs:	X = the offset to the record that was changed.
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	with Globals

	sta RecordIndex

	pha	; space for handle
	pha
	PushLong LEHandle
	_LEGetTextHand	; get the text from Line Edit
	PullLong TempHandle

	pha
	PushLong LEHandle
	_LEGetTextLen	; find out how large it is.
	PullWord StringSize

	pha	; make room for NewHandle result
	pha
	PushWord #0	; push handle size that we want
	lda StringSize	; but add 1 to it to take into
	inc a	; account the string length byte
	pha
	PushWord MyID
	PushWord #attrFixed+attrNoCross
	PushLong #0
	_NewHandle	; create a handle for the string

; save the handle we got in 'StringHandle' so that we can later store it in the
; member's record. Also store it in 'deref' so that we can dereference it. The
; macro PullLong addr1,addr2 will do that for us in one step!

	PullLong StringHandle,deref

	ldy #2	; dereference the String Handle to get
	lda [deref],y	; just a pointer.
	tax
	lda [deref]
	sta deref
	stx deref+2

	lda StringSize	; create a Pascal string from the lineEdit
	sta [deref]	; item for the List Manager

; Copy the LineEdit string into the string's handle. However, set the
; destination to be the second byte of the handle, as we need to put the
; length of the string in the first byte.

	PushLong TempHandle	; handle of the source string
	lda deref+2	; deref holds a pointer to the start
	pha	; of the destination, but we have to bump
	lda deref	; by one to account for the length byte
	inc a	; that we have to stick there.
	pha
	PushWord #0	; bytes to transfer must be LONG, so
	PushWord StringSize	; create a high byte of zero.
	_HandToPtr

; initialize the data in the member record we are creating.

	ldx RecordIndex
	lda deref	; get low word of address of new string
	sta MyData,x	; and save it
	lda deref+2	; and now the high word
	sta MyData+2,x
	lda #0	; store a memflag byte
	sta MyData+4,x
	lda StringHandle	; store the handle to the string so that
	sta MyData+6,x	; we can easily dispose of it later.
	lda StringHandle+2
	sta MyData+8,x

	rts

StringHandle	ds.b 4
TempHandle	ds.b 4
StringSize	ds.b 2
RecordIndex	ds.b 2

	ENDP

	EJECT
*******************************************************************************
*
DisposeMember	PROC
*
* Description:	Find the currently hilited list member and and return
*	with an offset to it. Will also dispose of any memory
*	associated with it to hold the displayed text.
*
*
* Inputs:	NONE
*
* Outputs:	X = offset from start of Member record array where the
*	    currently hilited member is stored.
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	with Globals

; Call _NextMember to find the hilited item. Calculate the offset
; within MyData of that record, and dispose of any string handles
; that may be there.

	pha	; space for result
	pha
	PushLong #0	; NIL to start at first entry
	PushLong #MyList	; pointer to my list record.
	_NextMember
	pla	; pointer to the next record
	plx	; discard the high byte
	sec	; subtract the front of the list to
	sbc #MyData	; get the offset into the table
	tax	; put into X so we can adjust the list
	stx recordIndex	; save it here for when we exit

	lda MyData+6+2,x	; See if there's a string handle by
	ora MyData+6,x	; checking for a NULL handle.
	beq done	; no string - so nothing to dispose of

	PushLong MyData+6,x	; get the string handle and dispose of it
	_DisposeHandle
done
	ldx RecordIndex	; return with offset in X register.
	rts

RecordIndex	ds.b 2

	ENDP


	EJECT
*******************************************************************************
*
NoSelection	PROC
*
* Description:	Set the activation state of the buttons to reflect the
*	fact that no list items are selected.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	PushWord #255	; deactivate the delete button
	PushLong DelBHdl	; handle to the delete button
	_HiLiteControl

	PushWord #255	; deactivate the reset button
	PushLong RstBHdl
	_HiLiteControl

	PushWord #255	; deactivate the replace button
	PushLong RepBHdl
	_HiLiteControl

	rts
	ENDP

	EJECT
*******************************************************************************
*
CreateCtrls	PROC
*
* Description:	Called at initialization time to create all of the
*	simple buttons we use.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	stz CCCount	; zero our counter
CCLoop
	lda CCCount	; get the next ctrl num to add
	asl a	; multiply it by four to make it an
	asl a	; offset into our control table
	tax	; now use it as an index
	lda MyCtrlList,x	; to get the pointer to the control data
	sta deref	; and save it in the DPage
	lda MyCtrlList+2,x	; so we can read it nicely
	sta deref+2
	stx tempWord	; save x for a moment

	pha	; space for result
	pha
	PushLong WindPointer ; pointer to my window

; Push on NewControl parameters. These parameters are obtained from tables
; in our Globals section. Each one is 'cRecSize' long, so we load the Y reg
; with that value (less 2), and use it to access all of the parameters in 
; the table, pushing each one on the stack as we go.

	ldy #cRecSize-2
CCL010	lda [deref],y	; Get these parameters from a list of
	pha	; data blocks in the Globals data
	dey	; section.
	dey
	bpl CCL010	; if not done, get the next one!

	_NewControl	; if so, then just call new control!

	ldx tempWord	; retrieve x
	pla	; and save the control handle
	sta MyCtlHdls,x
	pla
	sta MyCtlHdls+2,x

	inc CCCount	; bump counter to get next record
	lda CCCount
	cmp NumCtrls	; test to see if we did the last one
	blt CCLoop	; if so, then just end

;
; Create the LineEdit item.
;
	pha	; space for result
	pha
	PushLong #destRect
	PushLong #destRect
	PushWord #20	; Allow only 20 chars in list item
	_LENew
	PullLong LEHandle

	rts

tempHandle	ds.B 4
CCCount	ds.B 2

	ENDP

	EJECT
*******************************************************************************
*
CreateList	PROC
*
* Description:	Called at initialization time to create the list item. It
*	simply calls _CreateList with a parameter block defined
*	in the Globals data section.
*
*
* Inputs:	NONE
*
* Outputs:	NONE
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	pha	; room for result
	pha
	PushLong WindPointer
	PushLong #MyList	; pointer to list rec
	_CreateList
	PullLong ListCtlHndl ; and get our list control handle

	rts
	ENDP

	EJECT
*******************************************************************************
*
doQuit	PROC
*
* Description:	Quit routine. Set the QuitFlag to TRUE for the EventLoop.
*
*
* Inputs:	NONE
*
* Outputs:	QuitFlag set to $FFFF
*
* External Refs:	NONE
*
* Entry Points:	NONE
*
*******************************************************************************
	With Globals

	lda #$FFFF
	sta QuitFlag
	rts
	ENDP

	Include 'lists.inits.aii'

	END

